﻿namespace SandScript.Plugin
{
    using System;
    using System.IO;
    using System.Reflection;
    using System.Windows.Forms;
    using System.Xml.XPath;
    using SandcastleBuilder.Utils;
    using SandcastleBuilder.Utils.BuildEngine;
    using SandcastleBuilder.Utils.PlugIn;

    public class SandScriptPlugin : IPlugIn
    {
        private static readonly string PluginName;
        private static readonly Version PluginVersion;
        private static readonly string PluginDescription;
        private static readonly string PluginCopyright;
        private static readonly ExecutionPointCollection PluginExecutionPoints;

        private IBuilder builder;
        private BuildProcess buildProcess;

        static SandScriptPlugin()
        {
            var assembly = Assembly.GetExecutingAssembly();
            var assemblyName = assembly.GetName();

            PluginName = GetAssemblyAttribute<AssemblyTitleAttribute>(assembly, x => x.Title);
            PluginVersion = assemblyName.Version;
            PluginDescription = GetAssemblyAttribute<AssemblyDescriptionAttribute>(assembly, x => x.Description);
            PluginCopyright = GetAssemblyAttribute<AssemblyCopyrightAttribute>(assembly, x => x.Copyright);

            PluginExecutionPoints = new ExecutionPointCollection
            {
                new ExecutionPoint(BuildStep.ValidatingDocumentationSources, ExecutionBehaviors.InsteadOf),
                new ExecutionPoint(BuildStep.GenerateSharedContent, ExecutionBehaviors.After),
                new ExecutionPoint(BuildStep.GenerateReflectionInfo, ExecutionBehaviors.InsteadOf)
            };
        }

        public SandScriptPlugin()
        {
            this.builder = Builder.Create();
        }

        #region Public Properties

        public string Name
        {
            get
            {
                return PluginName;
            }
        }

        public string Description
        {
            get
            {
                return PluginDescription;
            }
        }

        public Version Version
        {
            get
            {
                return PluginVersion;
            }
        }

        public string Copyright
        {
            get
            {
                return PluginCopyright;
            }
        }

        public ExecutionPointCollection ExecutionPoints
        {
            get
            {
                return PluginExecutionPoints;
            }
        }

        public bool RunsInPartialBuild
        {
            get
            {
                return false;
            }
        }

        #endregion

        #region Public Methods

        public string ConfigurePlugIn(SandcastleProject project, string currentConfig)
        {
            MessageBox.Show("The SandScript plugin has no configurable settings", "SandScript Plugin", MessageBoxButtons.OK, MessageBoxIcon.Information);

            return currentConfig;
        }

        public void Initialize(BuildProcess buildProcess, XPathNavigator configuration)
        {
            this.buildProcess = buildProcess;
            this.buildProcess.ReportProgress("{0} Version {1}\r\n{2}\r\n", PluginName, PluginVersion, PluginCopyright);
        }

        public void Execute(ExecutionContext context)
        {
            switch (context.BuildStep)
            {
                case BuildStep.ValidatingDocumentationSources:
                    ValidateDocumentationSources(this.buildProcess);
                    context.Executed = true;
                    break;
                case BuildStep.GenerateSharedContent:
                    GenerateSharedContent(this.buildProcess);
                    context.Executed = true;
                    break;
                case BuildStep.GenerateReflectionInfo:
                    GenerateReflectionInfo(this.buildProcess);
                    context.Executed = true;
                    break;
            }
        }

        public void Dispose()
        {
        }

        #endregion

        #region Private Methods

        private static void ValidateDocumentationSources(BuildProcess buildProcess)
        {
            buildProcess.ExecuteBeforeStepPlugIns();

            foreach (var item in buildProcess.CurrentProject.DocumentationSources)
            {
                var extension = Path.GetExtension(item.SourceFile.ExpandedPath);

                switch (extension)
                {
                    case ".js":
                    case ".htm":
                    case ".html":
                        buildProcess.ReportProgress("Ready to process {0}.", item.SourceFile.ExpandedPath);
                        break;
                }
            }

            buildProcess.ExecuteAfterStepPlugIns();
        }

        private static void GenerateReflectionInfo(BuildProcess buildProcess)
        {
        }

        private static void GenerateSharedContent(BuildProcess buildProcess)
        {
            buildProcess.ExecuteBeforeStepPlugIns();
            //// buildProcess.ExecuteAfterStepPlugIns();
        }

        private static string GetAssemblyAttribute<T>(Assembly assembly, Func<T, string> memberExpression)
            where T : Attribute
        {
            var attributes = assembly.GetCustomAttributes(typeof(T), false);

            if (attributes.Length > 0)
            {
                return memberExpression.Invoke((T)attributes[0]);
            }

            return string.Empty;
        }

        #endregion
    }
}
